Conversation
Caught by vhsm-d1f4 2026-04-28 during the #191 release-gate fresh- install verification: \`AIRC_CHANNEL=canary curl|bash\` silently landed on main, requiring a follow-up \`airc canary && airc update\` dance. The fresh-install branch (line 495 pre-fix) was \`git clone\` without specifying a branch, so it defaulted to the repo's default (main) regardless of the env var. The update-existing branch already honored \$SAVED_CHANNEL via \$CLONE_DIR/.channel; only the cold-start path was broken. Fix: 1. \$CHANNEL_TARGET = \${AIRC_CHANNEL:-main}, validated against the known list (main, canary) — unknown values fall back to main with a warning rather than failing later with an obscure git error. 2. \`git clone --branch \$CHANNEL_TARGET\` lands directly on the requested branch. 3. Write \$CLONE_DIR/.channel after clone so future \`airc update\` stays on the same channel (matches what \`airc canary\` / \`airc main\` would write). Verified locally: AIRC_CHANNEL=canary lands on canary HEAD; default lands on main; bogus value falls back to main with the warning.
There was a problem hiding this comment.
Pull request overview
Updates the install.sh first-install path to respect the requested release channel (e.g., canary) so fresh installs land on the intended branch and persist that choice for future updates.
Changes:
- On first install, select a channel target from
AIRC_CHANNEL(defaultmain) and validate it against known channels. - Clone the repo using
git clone --branch <channel>so the checkout lands on the desired branch immediately. - Persist the chosen channel to
$CLONE_DIR/.channelto keep subsequentairc updatealigned.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| # First install. Honor AIRC_CHANNEL if set so users can land on canary | ||
| # directly via `AIRC_CHANNEL=canary curl|bash` without a follow-up | ||
| # `airc canary && airc update` dance. Default to main (the release |
…l ask) Joel 2026-04-28: "is anyone running claude or codex from inside powershell?" — basically nobody. Real users are in Git Bash via Claude Code / Codex on Windows, and we were forcing them to switch shells just to install. Bad onboarding. install.sh on MSYS already covered most of the Windows setup (winget prereqs, OpenSSH.Server capability, HNS port-22, firewall, sshd start). Two gaps closed here: 1. **DefaultShell registry write** (#98). The elevated PowerShell payload now also writes HKLM:\SOFTWARE\OpenSSH\DefaultShell to Git for Windows bash.exe. Without this, every Windows airc HOST silently fails inbound `airc msg` because OpenSSH's default shell is cmd.exe, which lacks `cat`, POSIX redirects, and the rest of the vocabulary airc remote commands assume. Bash candidates + PATH lookup + idempotent registry write. 2. **Tailscale via winget** (#94). install_tailscale's case statement now has an MSYS branch using `winget install --id Tailscale.Tailscale` (proper case — winget --exact is case-sensitive). Previously install.sh on Git Bash skipped Tailscale entirely. Result: a Windows user pasting AIRC_CHANNEL=canary bash -c "$(curl -fsSL https://raw.githubusercontent.com/CambrianTech/airc/canary/install.sh)" into their Git Bash terminal gets the FULL Windows host setup in one shot — winget prereqs + Tailscale + sshd + DefaultShell — without ever opening a PowerShell window. One UAC prompt for the elevated sshd payload, that's it. install.ps1 stays for the edge case where someone wants airc.ps1 (PowerShell-native) — that path still installs pwsh + wires airc.cmd / airc.ps1 to %USERPROFILE%\AppData\Local\Programs\airc, which bash install.sh deliberately does not (Git Bash users use the bash airc via ~/.local/bin).
…s Git Bash) Joel 2026-04-28: \"is anyone running claude or codex from inside powershell?\" — basically nobody. Real users on Windows are in Git Bash via Claude Code / Codex / Cursor / opencode / Windsurf / openclaw. Pointing them at install.ps1 and 'open PowerShell' was bad onboarding that we have to get perfect or we get no users. Demote install.ps1 to a side note for the rare native-PowerShell user who specifically wants airc.ps1. Lead with bash install.sh as the universal entry point. The companion install.sh changes (in this same PR) make MSYS path bulletproof: winget prereqs + Tailscale + sshd capability + HNS port-22 + firewall + DefaultShell=bash.exe, all behind one UAC prompt. Two install sections updated (top, and the Setup block at line 120). Skills already used the bash form everywhere so no skill changes needed.
There was a problem hiding this comment.
Pull request overview
This PR updates the installation flow to make install.sh the canonical Windows install path when running from Git Bash (MSYS), aligning onboarding with Claude Code / Codex usage patterns and closing key Windows-host gaps (channel selection, OpenSSH DefaultShell, Tailscale install).
Changes:
- Honor
AIRC_CHANNELon first install by cloning the requested branch (main/canary) and persisting it to.channel. - Extend Windows (Git Bash) sshd setup to also configure OpenSSH
DefaultShellto Git Bashbash.exe. - Add a Windows Git Bash (MSYS)
wingetpath for optional Tailscale install using the canonicalTailscale.TailscaleID.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| install.sh | Adds Windows Git Bash support improvements: DefaultShell registry write, winget-based Tailscale install branch, and AIRC_CHANNEL-aware first clone. |
| README.md | Updates docs to position install.sh as the primary install command for all platforms including Windows Git Bash, with install.ps1 as an alternative for native PowerShell users. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| Start-Service sshd; | ||
| Set-Service -Name sshd -StartupType Automatic; | ||
| Write-Host "airc: sshd ready (capability + HNS + firewall + service auto-start)"; | ||
| $bashCandidates = @("C:\Program Files\Git\bin\bash.exe", "C:\Program Files (x86)\Git\bin\bash.exe", "$env:USERPROFILE\AppData\Local\Programs\Git\bin\bash.exe"); |
…there when it just got installed Joel 2026-04-28: 'Cross lan mesh? tailscale is optional but recommended. Well guess fucking what it is installed sooooo. fail?' The end-of-install banner unconditionally printed 'Tailscale is optional but recommended: https://tailscale.com' even after winget had just installed it 30 seconds earlier. Reads as 'install failed' to the user. Three states now handled: - Not installed → show the optional/URL line (was always shown) - Installed, logged out → ts_post_check warns + shows sign-in path - Installed, logged in → silent (best UX) Plus extend ts_post_check + tailscale_present to find Tailscale on Windows Git Bash (`/c/Program Files/Tailscale/tailscale.exe`) — winget installs there, PATH may not include it in the current shell yet, so the bare `command -v tailscale` would have returned false and the post install would have nagged users to install something already installed.
Joel 2026-04-28: "is anyone running claude or codex from inside powershell?" — no. Users are in Git Bash via Claude Code / Codex on Windows. We were forcing them to switch shells just to install. Bad onboarding, and onboarding is what determines whether users stay or bail.
This PR makes `bash install.sh` on Git Bash (MSYS) the canonical Windows install path. install.ps1 stays around for users who specifically want `airc.ps1` (PowerShell-native), but Git Bash / Claude Code / Codex users no longer need to touch PowerShell.
What's in here
AIRC_CHANNEL honored on fresh install (vhsm-d1f4's catch). `AIRC_CHANNEL=canary curl|bash` now lands on canary instead of silently dropping to main. `git clone --branch $CHANNEL_TARGET`, validates against {main, canary}, persists to `.channel` for future updates.
DefaultShell registry write (bug: install.ps1 — DefaultShell unconfigured; Windows airc message delivery fails (cmd.exe lacks 'cat') #98). The MSYS elevated PowerShell payload now also writes `HKLM:\SOFTWARE\OpenSSH\DefaultShell` to Git for Windows `bash.exe`. Without this, every Windows airc HOST silently fails inbound `airc msg` because OpenSSH's default shell is cmd.exe.
Tailscale via winget on MSYS (bug: install.ps1 — Tailscale winget package ID typo (lowercase) causes silent install failure #94). `install_tailscale` gains a MINGW branch using `winget install --id Tailscale.Tailscale` (proper case).
Result
Single command from any shell on Windows:
```
AIRC_CHANNEL=canary bash -c "$(curl -fsSL https://raw.githubusercontent.com/CambrianTech/airc/canary/install.sh)\"
```
Does the full Windows host setup — winget prereqs + Tailscale + sshd capability + HNS port-22 reservation + firewall rule + sshd start + DefaultShell=bash — in one shot. One UAC prompt for the elevated sshd payload. No PowerShell shell switching.
Test plan
🤖 Generated with Claude Code